package service

import (
	"context"
	"database/sql"
	"encoding/json"
	"errors"
	"fx_swift_schedule/api"
	"fx_swift_schedule/internal/model"
	"fx_swift_schedule/pkg/code"
	"fx_swift_schedule/pkg/global"
	"fx_swift_schedule/pkg/gorsa"
	"fx_swift_schedule/pkg/httputils"
	"fx_swift_schedule/pkg/internalerrors"
	"fx_swift_schedule/pkg/logger"
	"fx_swift_schedule/pkg/utils"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"io"
	"net/http"
	"net/url"
)

// 请求OTTPay参数封装
func OperatorParamToPost(tradeCode, accessToken string, body []byte) ([]byte, error) {
	var (
		err  error
		resp string
		url  string
	)
	url = global.ViperObj.GetString("ottpay.baseUrl") + tradeCode
	//组装请求头参数
	reqMap := httputils.GetRequestParam(tradeCode, accessToken)
	//组装请求体参数
	reqBody := make(map[string]interface{})
	err = json.Unmarshal(body, &reqBody)
	if err != nil {
		return nil, err
	}
	reqMap["body"] = reqBody

	//转换成byte
	jsonData, err := json.Marshal(reqMap)

	//请求参数加密
	request := utils.Encrtpt(string(jsonData), global.ViperObj.GetString("ottpay.merChantNo"))
	reqJson, _ := json.Marshal(request)
	resp = httputils.DoPost(url, reqJson)

	var resBean = &api.Bean{}
	err = json.Unmarshal([]byte(resp), &resBean)
	if err != nil {
		logger.SugarLogger.Error(err)
		return nil, err
	}
	//解密并且封装实体
	resStr, err := utils.Decrypt(resBean)
	if err != nil {
		logger.SugarLogger.Error(err)
		return nil, err
	}
	headObj := &api.JsonStr{}
	err = json.Unmarshal(resStr, &headObj)
	//校验返回结果是否有异常，有则返回异常信息
	if headObj.Head.RespDesc != "请求成功" && headObj.Head.RespDesc != "S00000" {
		return nil, errors.New(headObj.Head.RespDesc)
	}
	return resStr, err
}

func DoDecrypt(body []byte) ([]byte, error) {
	//logger.SugarLogger.Infof("请求body打印：%s", string(body))
	var resBean = &api.Bean{}
	err := json.Unmarshal(body, &resBean)
	if err != nil {
		logger.SugarLogger.Errorf("json 读取报错:%w", err)
		return nil, err
	}

	//解密并且封装实体
	resStr, err := utils.Decrypt(resBean)
	if err != nil {
		logger.SugarLogger.Errorf("响应报文解密报错:%w", err)
		return nil, err
	}

	return resStr, err
}

func PostTp1013(req *api.Tp1013Req, merchantToken string) (*api.Tp1013Res, error) {
	var (
		err    error
		body   []byte
		resStr []byte
	)
	body, err = json.Marshal(&req)
	if err != nil {
		logger.SugarLogger.Errorf("json转换:%w", err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	resStr, err = OperatorParamToPost("tp1013", merchantToken, body)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	ottPayResult := &api.Tp1013Res{}
	err = json.Unmarshal(resStr, &ottPayResult)
	if err != nil {
		logger.SugarLogger.Errorf("json转换:%w", err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	return ottPayResult, err
}

func PostTp3001(req *api.Tp3001Req, merchantToken string) (*api.Tp3001Res, error) {
	var (
		err    error
		body   []byte
		resStr []byte
	)
	body, err = json.Marshal(&req)
	if err != nil {
		logger.SugarLogger.Errorf("json转换:%w", err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	resStr, err = OperatorParamToPost("tp3001", merchantToken, body)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	ottPayResult := &api.Tp3001Res{}
	err = json.Unmarshal(resStr, &ottPayResult)
	if err != nil {
		logger.SugarLogger.Errorf("json转换:%w", err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	return ottPayResult, err
}

func Tp1014(req *api.Tp1014Req, merchantToken string) error {
	var (
		err  error
		body []byte
	)
	body, err = json.Marshal(&req)
	if err != nil {
		logger.SugarLogger.Errorf("json转换:%w", err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	_, err = OperatorParamToPost("tp1014", merchantToken, body)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	return err
}

func OperatorParams(url string, req interface{}) (string, error) {
	var (
		err       error
		resultStr string
		body      []byte
	)
	body, err = json.Marshal(&req)
	if err != nil {
		return "", internalerrors.New(code.ErrUnknown, err.Error())
	}
	resultStr, err = sendRequestToGep(url, string(body))
	if err != nil {
		return "", internalerrors.New(code.ErrUnknown, err.Error())
	}
	return resultStr, err
}

func sendRequestToGep(urls, params string) (string, error) {
	var (
		err     error
		body    []byte
		resp    *http.Response
		respObj *api.GenResponseVo
	)
	// 私钥加密
	prienctypt_str, err := gorsa.PriKeyEncrypt(params, gorsa.GetPrivateKeyStr())
	if err != nil {
		return "", err
	}
	// 将 formData 转换为 application/x-www-form-urlencoded 格式
	formData := url.Values{}
	formData.Set("version", "1.0.0")
	formData.Set("certificateId", global.ViperObj.GetString("gep.certificateId"))
	formData.Set("userNo", global.ViperObj.GetString("gep.userNo"))
	formData.Set("dataType", "JSON")
	formData.Set("dataContent", prienctypt_str)

	headers := map[string]string{
		"Content-Type": "application/x-www-form-urlencoded",
	}
	resp, err = httputils.HTTPPost(urls, headers, []byte(formData.Encode()))
	if resp == nil {
		return "", err
	}
	if resp.StatusCode != 200 || err != nil {
		return "", err
	}
	body, err = io.ReadAll(resp.Body)
	//fmt.Printf("返回数据：%s", string(body))
	err = json.Unmarshal(body, &respObj)
	if err != nil {
		return "", err
	}
	if respObj.Success == true {
		return respObj.Result, err
	} else {
		return "", errors.New(respObj.ErrorMsg)
	}
}

// 退款&&销卡
func RefundBalance(amount float64, agentAccount, bossAccount, recordType, recordDesc string) error {
	var (
		sqlRecord    sql.Result
		rowsAffected int64
		err          error
		accountObj   *model.FxAccount
	)
	db := g.DB().Schema("card")
	// 代理商金额变动
	return db.Transaction(nil, func(ctx context.Context, tx gdb.TX) error {
		if sqlRecord, err = tx.Model("fx_account").Data("balance = balance + ?", amount).
			Where("account_type='agent' and account=?", agentAccount).Update(); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}

		rowsAffected, _ = sqlRecord.RowsAffected()
		if rowsAffected == 0 {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, "数据库更新失败")
		}

		if err = tx.Model("fx_account").
			Where("account=?", agentAccount).Scan(&accountObj); err != nil {

			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		// 金额流水记录
		if _, err = tx.Model("fx_record").Insert(&model.FxRecord{
			DiscountOrderNo:  utils.GenerateCode64(),
			Account:          agentAccount,
			ActualAmount:     amount,
			Amount:           amount,
			BudgetSign:       1,
			AccountType:      "agent",
			RecordType:       recordType,
			Desc:             recordDesc + "入账",
			RemainingBalance: accountObj.Balance.InexactFloat64(),
		}); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}

		// Boss
		if sqlRecord, err = tx.Model("fx_account").Data("balance = balance + ?", amount).
			Where("account='admin' and account_type='boss'").Update(); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}

		rowsAffected, _ = sqlRecord.RowsAffected()
		if rowsAffected == 0 {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, "数据库更新失败")
		}

		if _, err = tx.Model("fx_record").Insert(&model.FxRecord{
			DiscountOrderNo: utils.GenerateCode64(),
			Account:         bossAccount,
			ActualAmount:    amount,
			Amount:          amount,
			BudgetSign:      1,
			AccountType:     "boss",
			RecordType:      recordType,
			Desc:            "充值入账",
		}); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}

		if sqlRecord, err = tx.Model("fx_account").Data("balance = balance - ?", amount).
			Where("balance-? >= 0 and account='admin' and account_type='boss'", amount).Update(); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}

		rowsAffected, _ = sqlRecord.RowsAffected()
		if rowsAffected == 0 {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, "数据库更新失败")
		}

		if _, err = tx.Model("fx_record").Insert(&model.FxRecord{
			DiscountOrderNo: utils.GenerateCode64(),
			Account:         bossAccount,
			ActualAmount:    amount,
			Amount:          amount,
			BudgetSign:      0,
			AccountType:     "boss",
			RecordType:      recordType,
			Desc:            recordDesc + "扣款",
		}); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		return nil
	})
}

// 从merchantNo文中获取ottPayToken
func GetMerchantToToken(merchantNo string) (string, error) {
	var (
		err         error
		redisResult *gvar.Var
	)
	redisResult, err = g.Redis().Get(context.Background(), merchantNo)
	if err != nil || redisResult.Val() == nil {
		logger.SugarLogger.Error(err)
		return "", nil
	}
	return redisResult.String(), err
}

// 通过商户号获取对应的代理商
func GetAccountToMerchantNo(merchantNo string) (string, error) {
	var (
		err            error
		companyUserObj *model.IfcgateCompanyUser
	)
	if err = global.GFDB.Ctx(context.Background()).Model("ifcgate_company_user").
		Where("merchant_no=?", merchantNo).Scan(&companyUserObj); err != nil {
		logger.SugarLogger.Error(err)
		return "", nil
	}
	return companyUserObj.AgentAccount, err
}
